package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"git-agent/config"
	xapp "git-agent/utils/app"
	"git-agent/utils/xcommand"
	"git-agent/utils/xgit"
	"git-agent/utils/xlog"
	"github.com/BurntSushi/toml"
	"github.com/kataras/iris"
	"github.com/kataras/iris/middleware/logger"

	//"github.com/kataras/iris/middleware/logger"
	irisRecover "github.com/kataras/iris/middleware/recover"
	"os"
	"strings"
)

var (
	HomeDir string = "/tmp/"
	ConfigFileSrc string = "config.toml"
	Config config.AutoGenerated
)


func init()  {
	xlog.Setup()

	//load config
	flag.StringVar(&ConfigFileSrc, "config", "config.toml", "configure file")
	flag.Usage = usage
}

func usage() {
	fmt.Fprintf(os.Stderr, `nginx version: nginx/1.10.0
Usage: git-agent -config=config.toml

Options:
`)
	flag.PrintDefaults()
}


func index(param *xgit.Params)  {
	if false == Commands.ExecBeforeCmd(param.Project) {
		err := errors.New("exec before cmd failed")
		app.Logger().Error(err)
		return
	}

	_, err := xgit.Pull(param)
	if xgit.RepositoryNotExists(err) {
		//不存在
		clone(param)
		if false == Commands.ExecInitCmd(param.Project) {
			err := errors.New("exec init cmd failed")
			app.Logger().Error(err)
		}
		if false == Commands.ExecAfterCmd(param.Project) {
			err := errors.New("exec after cmd failed")
			app.Logger().Error(err)
		}
		return;
	}
	if err != nil {
		app.Logger().Error(err)
		return
	}

	if false == Commands.ExecAfterCmd(param.Project) {
		err := errors.New("exec after cmd failed")
		app.Logger().Error(err)
	}
}

func pull(param *xgit.Params)  {
	_, err := xgit.Pull(param)
	if err != nil {
		app.Logger().Error(err)
		return
	}
}

func clone(param *xgit.Params)  {
	_, err  := xgit.Clone(param)
	if err != nil {
		app.Logger().Error(err)
	}
}

func loadConfig()  {
	newConfig, err := toml.DecodeFile(ConfigFileSrc, &Config);
	if err != nil {
		app.Logger().Error(err)
		return
	}

	byteData, _ := json.Marshal(newConfig)
	app.Logger().Debug("New Config: ",string(byteData))

	for _, item := range Config.Projects {
		xlog.Info.Println("Add cmd config", item.Cmd)
		Commands.AddCmd(item.Name, &xcommand.Cmd{
			Dir: item.Path,
			Before: item.Cmd.Before,
			Init:   item.Cmd.Init,
			After:  item.Cmd.After,
		})
	}
}

var app *iris.Application

func main()  {
	flag.Parse()

	app = iris.New()

	app.Logger().SetLevel("debug")

	xgit.Setup(app.Logger())
	logger.New()

	app.Use(irisRecover.New())

	loadConfig()



	app.Get("/index", func(ctx iris.Context) {
		handle("index", ctx)
	})
	app.Post("/index", func(ctx iris.Context) {
		handle("index", ctx)
	})

	app.Get("/pull", func(ctx iris.Context) {
		handle("pull", ctx)
	})
	app.Post("/pull", func(ctx iris.Context) {
		handle("pull", ctx)
	})

	app.Get("/clone", func(ctx iris.Context) {
		handle("clone", ctx)
	})
	app.Post("/clone", func(ctx iris.Context) {
		handle("clone", ctx)
	})

	app.Get("/update-config", func(ctx iris.Context) {
		handleUpdateConfig(ctx)
	})

	go service()
	app.Run(iris.Addr(Config.Service.Addr), iris.WithoutServerError(iris.ErrServerClosed))
}

type Task struct {
	Action string
	Params *xgit.Params
}

var queues chan *Task = make(chan *Task, 100)

func handleUpdateConfig(ctx iris.Context)  {
	apps := xapp.New(ctx)
	loadConfig()
	xlog.Info.Println("config:", Config.Projects)
	apps.Response.EndSuccess(iris.Map{"action": "update-config"})

}

var Commands = xcommand.New()

func handle(action string, ctx iris.Context)  {
	apps := xapp.New(ctx)

	params := xgit.Params{}

	params.Project  = ctx.URLParam("project")
	params.RefType = ctx.URLParamDefault("ref_type", "tag")
	params.RefName = ctx.URLParamDefault("ref_name", "")

	for _, item := range Config.Projects{
		if 0 == strings.Compare(item.Name, params.Project) {
			params.URL = item.URL
			params.Path = item.Path
			if len(item.RefType) > 0 {
				params.RefType = item.RefType
			}
			if len(item.RefName) > 0 {
				params.RefName = item.RefName
			}
		}
	}

	if len(params.Project) == 0 {
		apps.Response.EndError(500, "project not exists.")
		return
	}

	if len(params.RefType) == 0 {
		apps.Response.EndError(500, "ref_type not exists.")
		return
	}

	if len(params.RefName) == 0 {
		xlog.Error.Println(params, Config.Projects)
		apps.Response.EndError(500, "ref_name not exists.")
		return
	}

	queues <- &Task{
		Action: action,
		Params: &params,
	}
	apps.Response.EndSuccess(iris.Map{"action": action, "project": params.Project, "url": params.URL, "ref_type": params.RefType, "ref_name": params.RefName})
}

func service()  {

	for {
		task, ok := <- queues
		if ok == true {
			if task.Action == "pull" {
				go pull(task.Params)
			} else if task.Action == "clone" {
				go clone(task.Params)
			} else if task.Action == "index" {
				go index(task.Params)
			}
		}
	}
}